package com.shanzmoo.h5.manager;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shanzmoo.base.bean.SResponse;
import com.shanzmoo.base.constant.Constant;
import com.shanzmoo.base.constant.MallOrderStatus;
import com.shanzmoo.base.constant.PayStatusConstant;
import com.shanzmoo.base.constant.e.PayTypeEnum;
import com.shanzmoo.base.constant.e.WxTradeTypeEnum;
import com.shanzmoo.base.exception.MallOrderException;
import com.shanzmoo.base.util.BillNoUtils;
import com.shanzmoo.base.util.MoneyUtils;
import com.shanzmoo.core.config.pay.PayServiceConfig;
import com.shanzmoo.core.domain.pay.PayOrderEntityLocalUtil;
import com.shanzmoo.core.domain.pay.PayResultResp;
import com.shanzmoo.core.domain.pay.WxWapPayResp;
import com.shanzmoo.core.pay.sdk.alipay.config.Configs;
import com.shanzmoo.core.service.IMallOrderRedisService;
import com.shanzmoo.core.service.IWxSpecialPayService;
import com.shanzmoo.db.mall.entity.MallOrderEntity;
import com.shanzmoo.db.mall.service.IMallOrderService;
import com.shanzmoo.db.personnel.entity.MemberInfoEntity;
import com.shanzmoo.db.personnel.service.IMemberInfoService;
import com.shanzmoo.db.trade.entity.PayOrderBodyEntity;
import com.shanzmoo.db.trade.entity.PayOrderEntity;
import com.shanzmoo.db.trade.service.IPayOrderBodyService;
import com.shanzmoo.db.trade.service.IPayOrderService;
import com.shanzmoo.h5.domain.OrderPayResult;
import com.shanzmoo.h5.domain.req.PayOrderByAliWebReq;
import com.shanzmoo.h5.domain.req.PayOrderByWxJsapReq;
import com.shanzmoo.h5.domain.req.PayOrderByWxMwebReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 *
 *
 * @author： Gzhao 2021/2/3
 */
@Slf4j
@Component
public class TradeManager {

    @Value("${trade.pay.aliPayCallBack}")
    private String aliCallBack;

    @Value("${trade.pay.aliReturnUrl}")
    private String aliReturnUrl;

    @Autowired
    private IMallOrderService mallOrderService;
    @Autowired
    private IPayOrderService payOrderService;
    @Autowired
    private IMemberInfoService memberInfoService;
    @Autowired
    private IWxSpecialPayService wxSpecialPayService;
    @Autowired
    private IMallOrderRedisService mallOrderRedisService;
    @Autowired
    private PayServiceConfig payServiceConfig;
    @Autowired
    private IPayOrderBodyService payOrderBodyService;


    @Transactional(rollbackFor = Exception.class)
    public String tradeByAliWap(PayOrderByAliWebReq request) throws AlipayApiException {
        MallOrderEntity order = obtainOrderByPay(request.getOrderNo());

        PayOrderEntity payOrder = createAliPayOrder(PayTypeEnum.Ali, order);
        PayOrderBodyEntity payOrderBody = PayOrderBodyEntity.create(payOrder.getPayNo());

        AlipayClient client = new DefaultAlipayClient(
                Configs.getOpenApiDomain(),
                Configs.getAppid(),
                Configs.getPrivateKey(),
                "json",
                "utf-8",
                Configs.getPublicKey(),
                Configs.getSignType());
        AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();

        // 封装请求支付信息
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(payOrder.getPayNo());
        model.setSubject(payOrder.getBody());
        model.setTotalAmount(MoneyUtils.dealWithTotalAmonut(payOrder.getTotalFee()));
        // 超时时间
        model.setTimeoutExpress("5m");
        model.setProductCode(order.getOrderNo() + "-001");
        alipay_request.setBizModel(model);
        // 设置异步通知地址
        alipay_request.setNotifyUrl(aliCallBack);
        // 设置同步通知地址
        alipay_request.setReturnUrl(aliReturnUrl + "?orderNo=" + payOrder.getOrderNo());

        payOrderBody.setReqBody(JSON.toJSONString(alipay_request));

        String form = client.pageExecute(alipay_request).getBody();

        payOrderBody.setRespBody(form);
        log.info("支付宝网页支付结果：{}", form);

        // 保存支付订单信息
        payOrderService.saveOrder(payOrder, payOrderBody);

        return form;
    }

    @Transactional(rollbackFor = Exception.class)
    public SResponse<WxWapPayResp> tradeBywxJsapPay(Integer memberId, PayOrderByWxJsapReq request) {
        MallOrderEntity order = obtainOrderByPay(request.getOrderNo());

        MemberInfoEntity member = memberInfoService.getById(memberId);
        if (member == null || StrUtil.isBlank(member.getOpenId())) {
            return SResponse.fail(Constant.ERRCODE_LOGIC, "未获取到会员微信身份信息");
        }
        // 1. 生产支付订单
        PayOrderEntity payOrder = createWxPayOrder(PayTypeEnum.Wx, WxTradeTypeEnum.JSAPI, order);
        PayOrderEntityLocalUtil.initOrder(payOrder);

        // 2. 向微信发送下单请求
        SResponse<WxWapPayResp> re = wxSpecialPayService.unifiedOrderByJsapi(member.getOpenId());

        // 保存支付订单信息
        payOrderService.saveOrder(PayOrderEntityLocalUtil.getPayOrderEntity(), PayOrderEntityLocalUtil.getPayOrderBodyEntity());

        return re;
    }


    @Transactional(rollbackFor = Exception.class)
    public SResponse<String> wxPayByMweb(PayOrderByWxMwebReq request) {
        MallOrderEntity order = obtainOrderByPay(request.getOrderNo());

        // 1. 生产支付订单
        PayOrderEntity payOrder = createWxPayOrder(PayTypeEnum.Wx, WxTradeTypeEnum.MWEB, order);
        PayOrderEntityLocalUtil.initOrder(payOrder);

        JSONObject sceneInfo = JSON.parseObject("{\"h5_info\": {\"type\":\"Wap\"," +
                "\"wap_url\": \"https://mall.jx.shanzhimoo.com\",\"wap_name\": \"嘉鑫优选\"}}");

        // 2. 向微信发送下单请求
        SResponse<String> re = wxSpecialPayService.unifiedOrderByMweb(sceneInfo.toJSONString());

        // 保存支付订单信息
        payOrderService.saveOrder(PayOrderEntityLocalUtil.getPayOrderEntity(), PayOrderEntityLocalUtil.getPayOrderBodyEntity());

        return re;
    }

    public SResponse<OrderPayResult> queryPayResult(String orderNo) {
        OrderPayResult result = new OrderPayResult();
        result.setOrderNo(orderNo);

        MallOrderEntity mallOrder = mallOrderService.getOne(
                new QueryWrapper<MallOrderEntity>()
                        .eq("order_no", orderNo)
        );
        result.setOrderId(mallOrder.getId());
        result.setReceiveAmount(mallOrder.getReceiveAmount());
        result.setReciveAddress(mallOrder.getDistrictStr() + " " + mallOrder.getAddress());

        List<PayOrderEntity> payOrderList = payOrderService.list(
                new QueryWrapper<PayOrderEntity>()
                        .eq("deleted", false)
                        .eq("status", true)
                        .eq("order_no", orderNo)
                        .orderByDesc("pay_status")
        );
        if (CollectionUtil.isEmpty(payOrderList)){
            result.setPayResult(Boolean.FALSE);
            return SResponse.ok(result);
        }

        for(PayOrderEntity payOrder : payOrderList){
            if (payOrder.getPayStatus() == PayStatusConstant.PAY_SUCCESS) {
                updateOrderPayInfo(mallOrder, payOrder);

                result.setPayResult(Boolean.TRUE);
                return SResponse.ok(result);
            }
            if (payOrder.getPayStatus().equals(PayStatusConstant.PAY_Fail)) {
                continue;
            }
            PayOrderEntityLocalUtil.setPayOrder(payOrder, payOrderBodyService.getByPayNo(payOrder.getPayNo()));

            SResponse<PayResultResp> re = payServiceConfig
                    .getPayService(EnumUtil.likeValueOf(PayTypeEnum.class, payOrder.getType()))
                    .queryPayResult(payOrder.getPayNo());
            if (re.isOk() && re.getData().isSuccess()){
                // 更新支付单信息
                PayOrderEntityLocalUtil.setReqBody(null);
                PayOrderEntityLocalUtil.setRespBody(null);
                payOrderService.updateByPayQuery(payOrder, PayOrderEntityLocalUtil.getPayOrderBodyEntity());

                updateOrderPayInfo(mallOrder, payOrder);

                PayOrderEntityLocalUtil.clear();

                result.setPayResult(Boolean.TRUE);
                return SResponse.ok(result);
            }
            PayOrderEntityLocalUtil.clear();
        }

        result.setPayResult(Boolean.FALSE);
        return SResponse.ok(result);
    }

    private MallOrderEntity obtainOrderByPay(String orderNo) {
        MallOrderEntity order = mallOrderService.getOne(
                new QueryWrapper<MallOrderEntity>()
                        .eq("deleted", false)
                        .eq("order_no", orderNo)
        );
        Assert.isTrue(order != null, "未获取到订单信息");


        if (order.getStatus() == MallOrderStatus.CLOSED) {
            throw new MallOrderException("订单已关闭，支付失败");
        }
        if (order.getPayStatus() || order.getStatus() != MallOrderStatus.WAIT_PAY){
            throw new MallOrderException("订单已支付，请勿重复支付");
        }
        return order;
    }

    private PayOrderEntity createAliPayOrder(PayTypeEnum payTypeEnum, MallOrderEntity order) {
        return PayOrderEntity.builder()
                .type(payTypeEnum.getCode())
                .payNo(BillNoUtils.generatePayNo())
                .orderNo(order.getOrderNo())
                .payStatus(PayStatusConstant.WAIT_PAY)
                .body("嘉鑫优选商城订单：" + order.getOrderNo())
                .totalFee(MoneyUtils.changeToFen(order.getReceiveAmount()))
                .build();
    }

    private PayOrderEntity createWxPayOrder(PayTypeEnum payTypeEnum, WxTradeTypeEnum wxTradeTypeEnum, MallOrderEntity order) {
        return PayOrderEntity.builder()
                .type(payTypeEnum.getCode())
                .payNo(BillNoUtils.generatePayNo())
                .orderNo(order.getOrderNo())
                .payStatus(PayStatusConstant.WAIT_PAY)
                .body("jx_mall_order：" + order.getOrderNo())
                .totalFee(MoneyUtils.changeToFen(order.getReceiveAmount()))
                .ip(NetUtil.getLocalhostStr())
                .tradeType(wxTradeTypeEnum.getDesc())
                .build();
    }

    /**
     * 更新支付信息
     * @param mallOrder
     * @param payOrder
     */
    private void updateOrderPayInfo(MallOrderEntity mallOrder, PayOrderEntity payOrder) {
        mallOrder.setPayStatus(true);
        mallOrder.setStatus(MallOrderStatus.WAIT_SEND);
        mallOrder.setPayType(payOrder.getType());
        mallOrder.setPayNo(payOrder.getPayNo());

        mallOrderService.updateById(mallOrder);
        mallOrderRedisService.updateOrder(mallOrder.getId());
    }
}
